﻿using System;
using System.Collections.Generic;
using System.Text;
using Selenium;

namespace SeleniumOrderPathRunner {
    public class AugmentedSelenium : DefaultSelenium {

        #region field variables
        public enum Compare { Is, IsNot, Has, HasNot };
        /// <summary>
        /// Defines 6 possible states in which a set of locators can exist. 
        /// All is defined as each item in the set existing.
        /// None is defined as no item in the set existing.
        /// Some is defined as at least one item existing and at least one item not existing.
        /// Combination states are the union of the two states, true if either state is true.
        /// </summary>
        public enum Set {All, Some, None, AllSome, AllNone, SomeNone };

        public enum TextContentType {LocatorText, LocatorAttribute, SelectorProperty};

        private HttpCommandProcessor commandProcess;
        #endregion



        public AugmentedSelenium( HttpCommandProcessor proc ) : base( proc ) {
            commandProcess = proc;
        }





        /// <summary>
        /// Gets the text contained directly in the locator. Inputs value are also obtained.
        /// Returns null if the element is not found.
        /// </summary>
        /// <param name="locator"></param>
        /// <returns></returns>
        private String getLocatorText(String locator) {
            if (!IsElementPresent(locator)) {
                return null;
            }

            String locatorValue;
            //try to determine if locator is an input(which doesn't 'contain' its text like other elements do
            try {
                if (locator.Split('/')[locator.Split('/').Length - 1].Contains("input")) {
                    locatorValue = GetValue(locator);
                } else {
                    locatorValue = GetText(locator);
                }
                return locatorValue;
            } catch (SeleniumException) {
                //Locator existence ended after check to confirm existence but before attempt to read text
                return null;
            }
            
        }


        /// <summary>
        /// Compares two strings. For positive cases, null s0 returns false(since null != s1). Similarly,
        /// null s0 returns true for negative cases.
        /// </summary>
        /// <param name="s0"></param>
        /// <param name="s1"></param>
        /// <param name="compareType"></param>
        /// <returns></returns>
        private bool textComparer(String s0, String s1, AugmentedSelenium.Compare compareType) {
            switch (compareType) {
                case Compare.Is:
                if (s0 == null) {
                    return false;
                }
                return s0.Equals(s1);
                case Compare.Has:
                if (s0 == null) {
                    return false;
                }
                return s0.Contains(s1);
                case Compare.IsNot:
                if (s0 == null) {
                    return true;
                }
                return !s0.Equals(s1);
                case Compare.HasNot:
                if (s0 == null) {
                    return true;
                }
                return !s0.Contains(s1);
                default:
                return false;
            }
        }

        /// <summary>
        /// wrapper function around the HTML command processor function to the js user-extension functions
        /// </summary>
        /// <param name="commandName">the name of the custom method, found in the user-extensions.js. 
        /// The name is formatted to remove the prefix 'do' and to lowercase the first letter following that prefix. </param>
        /// <param name="commandParams">Not quite sure how this works yet. Are each param treated as a single var
        /// for in the set of params for the custom method?</param>
        private void runProcCommand( String commandName, String[] commandParams ) {
            commandProcess.DoCommand( commandName, commandParams );
            
        }


        #region is element methods
        /// <summary>
        /// Looks for a set of selectors and if any exist, compares their value of a specified property to a set of specified values. 
        /// </summary>
        /// <param name="selectors">The set of css selectors</param>
        /// <param name="compareType">The logical test to perform</param>
        /// <param name="property">The specific css selector property to evaluate</param>
        /// <param name="values">The set of values to compare against all the values of the selector.property set</param>
        /// <param name="browser">Necessary to determine native JS function to get css</param>
        /// <returns>For positive comparisons, returns true if the value of any selector.property satisfies the compareType.
        /// For negative comparisons, returns false if the value of any selector.property does not satisfy the compareType.</returns>
        public bool isCssSelectorProperty(String[] selectors, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String property, String[] values, SeleniumServer.Browser browser) {
            if (selectors == null) {
                throw new ArgumentNullException("selectors", "selectors must not be null.");
            }
            if (values == null) {
                throw new ArgumentNullException("values", "At least one value must be supplied.");
            }
            if (values.Length < 1) {
                throw new ArgumentException("values", "At least one value must be supplied.");
            }
            
            String cssRules = "";
            switch (browser) {
                case SeleniumServer.Browser.Firefox:
                cssRules = "cssRules";
                break;
                case SeleniumServer.Browser.IExplore:
                cssRules = "rules";
                break;
            }
            String jsTop = @" var cssSelectorPropertyValue = 'ThisSelectorDoesNotExist';
                            for(var x = 0; x < window.document.styleSheets.length; x++){
                                for(var y = 0; y < window.document.styleSheets[x]." + cssRules + @".length; y++){
                                    if(window.document.styleSheets[x]." + cssRules + @"[y].selectorText == '"; /* + selector + */ 
            String jsBottom = @"'){
                                        cssSelectorPropertyValue = window.document.styleSheets[x]." + cssRules + @"[y].style."+property+@";
                                    }
                                }
                            }
                            cssSelectorPropertyValue;";
            //work around not first checking if the selector exists and losing that info when returning '' from the js:
            //set the return value to something uniquely recognizable initially, then watch for that text and then set the string to null

            switch (existType) {
                case Set.All:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (!comparisonMet) {
                        return false;
                    }
                }
                return true;
                case Set.AllNone:
                bool foundSelectorPropertyComparisonMatch = false;
                bool foundSelectorPropertyComparisonNotMatch = false;
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        foundSelectorPropertyComparisonMatch = true;
                    } else {
                        foundSelectorPropertyComparisonMatch = true;
                    }
                    if (foundSelectorPropertyComparisonMatch && foundSelectorPropertyComparisonNotMatch) {
                        return false;
                    }
                }
                return (foundSelectorPropertyComparisonMatch && !foundSelectorPropertyComparisonNotMatch) || (!foundSelectorPropertyComparisonMatch && foundSelectorPropertyComparisonNotMatch);
                case Set.AllSome:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            return true;
                        }
                    }
                }
                return false;
                case Set.None:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            return false;
                        }
                    }
                }
                return true;
                case Set.Some:
                bool foundSelectorPropertyComparisonMatch1 = false;
                bool foundSelectorPropertyComparisonNotMatch1 = false;
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        foundSelectorPropertyComparisonMatch1 = true;
                    } else {
                        foundSelectorPropertyComparisonMatch1 = true;
                    }
                    if (foundSelectorPropertyComparisonMatch1 && foundSelectorPropertyComparisonNotMatch1) {
                        return true;
                    }
                }
                return foundSelectorPropertyComparisonMatch1 && foundSelectorPropertyComparisonNotMatch1;
                case Set.SomeNone:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                        }
                    }
                    if (comparisonMet == false) {
                        return true;
                    }
                }
                return false;
            }
            return false;
        }





        /// <summary>
        /// Searches all available CSS files for each selector specified,
        /// and returns value of the set match type specified.
        /// 
        /// Currently, the js function is extremely suboptimal. It searches the entire CSS 
        /// selector set, for a single selector in question then repeats for the next selector
        /// specified for a O(s^2) cost.
        /// </summary>
        /// <param name="selector">The element type for which the CSS styling is applied</param>
        /// <param name="existType"></param>
        /// <param name="browser">Needed to know how to create the js call to the browser </param>
        /// <returns></returns>
        public bool isCssSelectorExistence(String[] selectors, AugmentedSelenium.Set existType, SeleniumServer.Browser browser) {
            if (selectors == null) {
                throw new ArgumentNullException("selectors", "selectors must not be null.");
            }
            String cssRules = "";
            switch (browser) {
                case SeleniumServer.Browser.Firefox:
                cssRules = "cssRules";
                break;
                case SeleniumServer.Browser.IExplore:
                cssRules = "rules";
                break;
            }
            String jsTop = @"  var elementExists = 'false';
                            for(var x = 0; x < window.document.styleSheets.length; x++){
                                for(var y = 0; y < window.document.styleSheets[x]." + cssRules + @".length; y++){
                                    if(window.document.styleSheets[x]." + cssRules + @"[y].selectorText == '";

            String jsBottom = @"'){
                                        elementExists = 'true';
                                    }
                                }
                            }
                            elementExists;";


            switch (existType) {
                case Set.All:
                foreach (String s in selectors) {
                    if (!(GetEval(jsTop + s + jsBottom).Equals("true"))) {
                        return false;
                    }
                }
                return true;
                case Set.AllSome:
                foreach (String s in selectors) {
                    if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                        return true;
                    }
                }
                return false;
                case Set.Some:
                bool foundExistingSelector = false;
                bool foundNotExistingSelector = false;
                foreach (String s in selectors) {
                    if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                        foundExistingSelector = true;
                    } else {
                        foundNotExistingSelector = true;
                    }
                }
                return foundExistingSelector && foundNotExistingSelector;
                case Set.None:
                foreach (String s in selectors) {
                    if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                        return false;
                    }
                }
                return true;
                case Set.AllNone:
                bool foundExistingSelector1 = false;
                bool foundNotExistingSelector1 = false;
                foreach (String s in selectors) {
                    if (IsElementPresent(s)) {
                        foundExistingSelector1 = true;
                    } else {
                        foundNotExistingSelector1 = true;
                    }
                }
                return (foundExistingSelector1 && !foundNotExistingSelector1) || (!foundExistingSelector1 && foundNotExistingSelector1);
                case Set.SomeNone:
                foreach (String s in selectors) {
                    if (!GetEval(jsTop + s + jsBottom).Equals("true")) {
                        return true;
                    }
                }
                return false;
            }
            return false;
        }





        /// <summary>
        /// Determines existence of a set of locators based on the set existence check specified.
        /// </summary>
        /// <param name="locators">A set of locators. Must contain at least one value, or an exception is thrown.</param>
        /// <param name="existType"></param>
        /// <returns></returns>
        public bool isLocatorExistence(String[] locators, AugmentedSelenium.Set existType) {
            if (locators == null) {
                throw new ArgumentNullException("locators", "At least one locator must be supplied.");
            }
            if (locators.Length < 1) {
                throw new ArgumentException("locators", "At least one locator must be supplied.");
            }
            switch (existType) {
                case Set.All:
                foreach (String s in locators) {
                    if (!IsElementPresent(s)) {
                        return false;
                    }
                }
                return true;
                case Set.AllSome:
                foreach (String s in locators) {
                    if (IsElementPresent(s)) {
                        return true;
                    }
                }
                return false;
                case Set.Some:
                bool foundExistingLocator = false;
                bool foundNotExistingLocator = false;
                foreach (String s in locators) {
                    if (IsElementPresent(s)) {
                        foundExistingLocator = true;
                    } else {
                        foundNotExistingLocator = true;
                    }
                }
                return foundExistingLocator && foundNotExistingLocator;
                case Set.None:
                foreach (String s in locators) {
                    if (IsElementPresent(s)) {
                        return false;
                    }
                }
                return true;
                case Set.AllNone:
                bool foundExistingLocator1 = false;
                bool foundNotExistingLocator1 = false;
                foreach (String s in locators) {
                    if (IsElementPresent(s)) {
                        foundExistingLocator1 = true;
                    } else {
                        foundNotExistingLocator1 = true;
                    }
                }
                return (foundExistingLocator1 && !foundNotExistingLocator1) || (!foundExistingLocator1 && foundNotExistingLocator1);
                case Set.SomeNone:
                foreach (String s in locators) {
                    if (!IsElementPresent(s)) {
                        return true;
                    }
                }
                return false;

                default:
                return false;
            }
        }






        /// <summary>
        /// 
        /// Will throw argument exceptions if no locators or values are specified
        /// </summary>
        /// <param name="locators">An array of locators.</param>
        /// <param name="compareType"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public bool isLocatorText(String[] locators, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String[] values) {
            if (locators == null) {
                throw new ArgumentNullException("locators", "Locators must not be null.");
            }
            if (locators.Length < 1) {
                throw new ArgumentException("locators", "At least one locator must be supplied.");
            }
            if (values == null) {
                throw new ArgumentNullException("values", "At least one value must be supplied.");
            }
            if (values.Length < 1) {
                throw new ArgumentException("values", "At least one value must be supplied.");
            }
            
            switch (existType) {
                case Set.All:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (!comparisonMet) {
                        return false;
                    }
                }
                return true;
                case Set.AllNone:
                bool foundLocatorTextComparisonMatch = false;
                bool foundLocatorTextComparisonNotMatch = false;
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        foundLocatorTextComparisonMatch = true;
                    } else {
                        foundLocatorTextComparisonNotMatch = true;
                    }
                    if (foundLocatorTextComparisonMatch && foundLocatorTextComparisonNotMatch) {
                        return false;
                    }
                }
                return (foundLocatorTextComparisonMatch && !foundLocatorTextComparisonNotMatch) || (!foundLocatorTextComparisonMatch && foundLocatorTextComparisonNotMatch);
                case Set.AllSome:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            return true;
                        }
                    }
                }
                return false;
                case Set.None:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            return false;
                        }
                    }
                }
                return true;
                case Set.Some:
                bool foundLocatorTextComparisonMatch1 = false;
                bool foundLocatorTextComparisonNotMatch1 = false;
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        foundLocatorTextComparisonMatch1 = true;
                    } else {
                        foundLocatorTextComparisonNotMatch1 = true;
                    }
                    if (foundLocatorTextComparisonMatch1 && foundLocatorTextComparisonNotMatch1) {
                        return true;
                    }
                }
                return foundLocatorTextComparisonMatch1 && foundLocatorTextComparisonNotMatch1;
                case Set.SomeNone:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                        }
                    }
                    if (comparisonMet == false) {
                        return true;
                    }
                }
                return false;
            }
            return false;
        }






        /// <summary>
        /// Compares a specified attribute value of the specified locators to the specified set of values.
        /// 
        /// Will throw argument exceptions if no locators or values are specified 
        /// </summary>
        /// <param name="locators">The locators whose attributes will be matched for</param>
        /// <param name="existType">The set comparision type</param>
        /// <param name="compareType">The equality to use for comparison</param>
        /// <param name="attribute">The attribute of the element whose value will be matched for</param>
        /// <param name="values">The values to be compared against the elements attributes values</param>
        /// <returns></returns>
        public bool isLocatorAttribute(String[] locators, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String attribute, String[] values) {
            if (locators == null) {
                throw new ArgumentNullException("locators", "Locators must not be null.");
            }
            if (values == null) {
                throw new ArgumentNullException("values", "At least one value must be supplied.");
            }
            if (values.Length < 1) {
                throw new ArgumentException("values", "At least one value must be supplied.");
            }

            switch (existType) {
                case Set.All:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try {
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    } catch (SeleniumException ) { }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (!comparisonMet) {
                        return false;
                    }
                }
                return true;
                case Set.AllNone:
                bool foundLocatorAttributeComparisonMatch = false;
                bool foundLocatorAttributeComparisonNotMatch = false;
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try {
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    } catch (SeleniumException) { }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        foundLocatorAttributeComparisonMatch = true;
                    } else {
                        foundLocatorAttributeComparisonNotMatch = true;
                    }
                    if (foundLocatorAttributeComparisonMatch && foundLocatorAttributeComparisonNotMatch) {
                        return false;
                    }
                }
                return (foundLocatorAttributeComparisonMatch && !foundLocatorAttributeComparisonNotMatch) || (!foundLocatorAttributeComparisonMatch && foundLocatorAttributeComparisonNotMatch);
                case Set.AllSome:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try {
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    } catch (SeleniumException ) { }
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            return true;
                        }
                    }
                }
                return false;
                case Set.None:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try {
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    } catch (SeleniumException ) { }
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            return false;
                        }
                    }
                }
                return true;
                case Set.Some:
                bool foundLocatorAttributeComparisonMatch1 = false;
                bool foundLocatorAttributeComparisonNotMatch1 = false;
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try {
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    } catch (SeleniumException ) { }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        foundLocatorAttributeComparisonMatch1 = true;
                    } else {
                        foundLocatorAttributeComparisonNotMatch1 = true;
                    }
                    if (foundLocatorAttributeComparisonMatch1 && foundLocatorAttributeComparisonNotMatch1) {
                        return true;
                    }
                }
                return foundLocatorAttributeComparisonMatch1 && foundLocatorAttributeComparisonNotMatch1;
                case Set.SomeNone:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try {
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    } catch (SeleniumException ) { }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                        }
                    }
                    if (comparisonMet == false) {
                        return true;
                    }
                }
                return false;
            }
            return false;
        }
        #endregion

        #region wait for element methods
        /// <summary>
        /// Waits until the specified condition for a set of locators is met, or the time specified elapses
        /// </summary>
        /// <param name="locators">The set of locators to be checked.</param>
        /// <param name="existType">The set comparison type.</param>
        /// <param name="timeout">The amount of time this function will wait for the specified condition to be met</param>
        /// <param name="interval">The time the thread sleeps between checking the set again</param>
        /// <returns>Returns true if the specified condition for the set of locators is met before the specified time elapses.</returns>
        public bool waitForLocatorExistence(String[] locators, AugmentedSelenium.Set existType, int timeout, int interval) {
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (!isLocatorExistence(locators, existType) && DateTime.Compare(start, DateTime.Now) > 0) {
                //timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
            return DateTime.Compare(start, DateTime.Now) > 0;
        }

        



        /// <summary>
        /// 
        /// </summary>
        /// <param name="locators"></param>
        /// <param name="existType"></param>
        /// <param name="compareType"></param>
        /// <param name="values"></param>
        /// <param name="timeout"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        public bool waitForText(String[] locators, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String[] values, int timeout, int interval) {
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (!isLocatorText(locators, existType, compareType, values) && DateTime.Compare(start, DateTime.Now) > 0) {
                //timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
            return DateTime.Compare(start, DateTime.Now) > 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="locators"></param>
        /// <param name="existType"></param>
        /// <param name="compareType"></param>
        /// <param name="attribute"></param>
        /// <param name="values"></param>
        /// <param name="timeout"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        public bool waitForAttribute(String[] locators, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String attribute, String[] values, int timeout, int interval) {
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (!isLocatorAttribute(locators, existType, compareType, attribute, values) && DateTime.Compare(start, DateTime.Now) > 0) {
                //timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
            return DateTime.Compare(start, DateTime.Now) > 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="selectors"></param>
        /// <param name="existType"></param>
        /// <param name="browser"></param>
        /// <param name="timeout"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        public bool waitForCssSelectorExistence(String[] selectors, AugmentedSelenium.Set existType, SeleniumServer.Browser browser, int timeout, int interval) {
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (!isCssSelectorExistence(selectors, existType, browser) && DateTime.Compare(start, DateTime.Now) > 0) {
                //timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
            return DateTime.Compare(start, DateTime.Now) > 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="selectors"></param>
        /// <param name="existType"></param>
        /// <param name="compareType"></param>
        /// <param name="property"></param>
        /// <param name="values"></param>
        /// <param name="browser"></param>
        /// <param name="timeout"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        public bool waitForCssSelectorProperty(String[] selectors, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String property, String[] values,  SeleniumServer.Browser browser, int timeout, int interval) {
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (!isCssSelectorProperty(selectors, existType, compareType, property, values, browser) && DateTime.Compare(start, DateTime.Now) > 0) {
                //timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
            return DateTime.Compare(start, DateTime.Now) > 0;
        }
        #endregion

        #region assert element methods
        /// <summary>
        /// Asserts existence of a set of locators based on the set existence check specified.
        /// </summary>
        /// <param name="locators">A set of locators. Must contain at least one value, or an ArgumentException is thrown.</param>
        /// <param name="existType"></param>
        /// <returns></returns>
        public void assertLocatorExistence(String[] locators, AugmentedSelenium.Set existType) {
            if (locators == null) {
                throw new ArgumentNullException("locators", "At least one locator must be supplied.");
            }
            if (locators.Length < 1) {
                throw new ArgumentException("locators", "At least one locator must be supplied.");
            }

            switch (existType) {
                case Set.All:
                    LinkedList<String> missingLocators = new LinkedList<string>();
                    foreach (String s in locators) {
                        if (!IsElementPresent(s)) {
                            missingLocators.AddLast(s);
                        }
                    }
                    if (missingLocators.Count > 0) {
                        TestAssertionException t0 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.Exist);
                        try {
                            t0.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) { }
                        foreach (String locator in missingLocators) {
                            t0.addLineToDataBottom("Expected locator : " + locator);
                        }
                        throw t0;
                    }
                return;
                case Set.AllSome:
                    foreach (String s in locators) {
                        if (IsElementPresent(s)) {
                            return;
                        }
                    }
                    TestAssertionException t1 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.Exist);
                    try {
                        t1.addLineToDataBottom("Current URL : " + GetLocation());
                    } catch (SeleniumException ) { }
                    t1.addLineToDataBottom("Expected at least one following locator :");
                    foreach (String locator in locators) {
                        t1.addLineToDataBottom("Locator : " + locator);
                    }
                    throw t1;
                case Set.Some:
                    LinkedList<String> existingLocators = new LinkedList<string>();
                    LinkedList<String> notExistingLocators = new LinkedList<string>();
                    foreach (String s in locators) {
                        if (IsElementPresent(s)) {
                            existingLocators.AddLast(s);
                        } else {
                            notExistingLocators.AddLast(s);
                        }
                    }
                    if(existingLocators.Count > 0 && notExistingLocators.Count > 0){
                        return;
                    }
                    if (notExistingLocators.Count == 0) {
                        TestAssertionException t2 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.NotExist);
                        try {
                            t2.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) { }
                        t2.addLineToDataBottom("Expected at least one locator to not exist:");
                        foreach (String locator in locators) {
                            t2.addLineToDataBottom("Locator : " + locator);
                        }
                        throw t2;
                    } else {
                        TestAssertionException t2 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.Exist);
                        try {
                            t2.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) { }
                        t2.addLineToDataBottom("Expected at least one locator to exist:");
                        foreach (String locator in locators) {
                            t2.addLineToDataBottom("Locator : " + locator);
                        }
                        throw t2;
                    }
                
                case Set.None:
                    LinkedList<String> existingLocators1 = new LinkedList<string>();
                    foreach (String s in locators) {
                        if (IsElementPresent(s)) {
                            existingLocators1.AddLast(s);
                        }
                    }
                    if (existingLocators1.Count > 0) {
                        TestAssertionException t3 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.NotExist);
                        try {
                            t3.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) { }
                        foreach (String locator in existingLocators1) {
                            t3.addLineToDataBottom("Unexpected locator : " + locator);
                        }
                        throw t3;
                    }
                return;
                case Set.AllNone:
                    LinkedList<String> existingLocator2 = new LinkedList<string>();
                    LinkedList<String> notExistingLocator2 = new LinkedList<string>();
                    foreach (String s in locators) {
                        if (IsElementPresent(s)) {
                            existingLocator2.AddLast(s);
                        } else {
                            notExistingLocator2.AddLast(s);
                        }
                    }
                    if (existingLocator2.Count > 0 && notExistingLocator2.Count > 0) {
                        TestAssertionException t4 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.Exist);
                        try {
                            t4.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) { }
                        t4.addLineToDataBottom("Expected all or no locators to exist, not some: ");
                        foreach (String locator in existingLocator2) {
                            //should all be present or none at all
                            t4.addLineToDataBottom("Existing locator : " + locator);
                        }
                        foreach (String locator in notExistingLocator2) {
                            //should all be missing or none at all
                            t4.addLineToDataBottom("Not existing locator : " + locator);
                        }
                        throw t4;
                    }
                return;
                case Set.SomeNone:
                    foreach (String s in locators) {
                        if (!IsElementPresent(s)) {
                            return;
                        } 
                    }
                    TestAssertionException t5 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.NotExist);
                    try {
                        t5.addLineToDataBottom("Current URL : " + GetLocation());
                    } catch (SeleniumException ) { }
                    t5.addLineToDataBottom("Expect at least one following locator to not exist :");
                    foreach (String locator in locators) {
                        t5.addLineToDataBottom("Unexpected any locator : " + locator);
                    }
                    throw t5;
            }
        }






        /// <summary>
        /// Asserts an equality/contains test on the set of locator texts and a set of supplied values.
        /// Throws a TestAssertionException if no element is satisfies the positive compare test or if
        /// any element does not satisfy the negative compare test.
        /// </summary>
        /// <param name="locators"></param>
        /// <param name="compareType"></param>
        /// <param name="values"></param>
        public void assertLocatorText(String[] locators, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String[] values){
            if (locators == null) {
                throw new ArgumentNullException("locators", "Locators must not be null.");
            }
            if (locators.Length < 1) {
                throw new ArgumentException("locators", "At least one locator must be supplied.");
            }
            if (values == null) {
                throw new ArgumentNullException("values", "At least one value must be supplied.");
            }
            if (values.Length < 1) {
                throw new ArgumentException("values", "At least one value must be supplied.");
            }

            List<KeyValuePair<String, String>> locatorsAndUnmatchingText = new List<KeyValuePair<string,string>>();
            List<KeyValuePair<String, String>> locatorsAndMatchingText   = new List<KeyValuePair<string,string>>();
            
            //better data struct?
            String valueComparisonString = compareType.ToString();

            switch (existType) {
                case Set.All:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (!comparisonMet) {
                        locatorsAndUnmatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                    }
                }
                if(locatorsAndUnmatchingText.Count == 0){
                    return;
                }
                TestAssertionException t0 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                t0.addLineToDataBottom("Expected: all locators text "+valueComparisonString+" some value specified");
                t0.addLineToDataBottom("Locators and their unexpected text:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingText){
                    t0.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t0.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t0.addLineToDataBottom(v);
                }
                throw t0;

                case Set.AllNone:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        locatorsAndMatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                    } else {
                        locatorsAndUnmatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                    }
                    if (locatorsAndMatchingText.Count > 0 && locatorsAndUnmatchingText.Count > 0) {
                        TestAssertionException t1 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                        t1.addLineToDataBottom("Expected: all or no locators text "+valueComparisonString+" some value specified");
                        t1.addLineToDataBottom("Locators and their unexpected text:");
                        foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingText){
                            t1.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                        }
                        foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingText){
                            t1.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                        }
                        t1.addLineToDataBottom("Specified values:");
                        foreach (String v in values) {
                            t1.addLineToDataBottom(v);
                        }
                        throw t1;
                    }
                }
                return;
                
                case Set.AllSome:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            return;
                        } 
                    }
                    locatorsAndUnmatchingText.Add(new KeyValuePair<string, string>(locator, locatorValue));
                }
                TestAssertionException t2 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                t2.addLineToDataBottom("Expected: One or more locators text "+valueComparisonString+" some value specified");
                t2.addLineToDataBottom("Locators and their unexpected text:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingText){
                    t2.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t2.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t2.addLineToDataBottom(v);
                }
                throw t2;
                
                case Set.None:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            locatorsAndMatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                            break;
                        }
                    }
                }
                if(locatorsAndMatchingText.Count > 0){
                    TestAssertionException t3 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                    t3.addLineToDataBottom("Expected: No locators text "+valueComparisonString+" some value specified");
                    t3.addLineToDataBottom("Locators and their unexpected text:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingText){
                        t3.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t3.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t3.addLineToDataBottom(v);
                    }
                    throw t3;
                }
                return;

                case Set.Some:                
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        locatorsAndMatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                    } else {
                        locatorsAndUnmatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                    }
                    if (locatorsAndMatchingText.Count > 0 && locatorsAndUnmatchingText.Count > 0) {
                        return;
                    }
                }                
                if(locatorsAndMatchingText.Count == 0){
                    TestAssertionException t4 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                    t4.addLineToDataBottom("Expected: One locators text "+valueComparisonString+" and one locators text isn't "+valueComparisonString+" some value specified");
                    t4.addLineToDataBottom("Locators and their unexpected text:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingText){
                        t4.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t4.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t4.addLineToDataBottom(v);
                    }
                    throw t4;
                }else{
                    TestAssertionException t4 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                    t4.addLineToDataBottom("Expected: One locators text "+valueComparisonString+" and one locators text isn't "+valueComparisonString+" some value specified");
                    t4.addLineToDataBottom("Locators and their unexpected text:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingText){
                        t4.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t4.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t4.addLineToDataBottom(v);
                    }
                    throw t4;
                }                
                
                case Set.SomeNone:
                foreach (String locator in locators) {
                    String locatorValue = getLocatorText(locator);
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorValue, value, compareType)) {
                            comparisonMet = true;
                            locatorsAndMatchingText.Add(new KeyValuePair<string,string>(locator, locatorValue));
                            break;
                        }
                    }
                    if (comparisonMet == false) {
                        return;
                    }
                }
                TestAssertionException t5 = new TestAssertionException(existType, compareType, TextContentType.LocatorText);
                t5.addLineToDataBottom("Expected: One or more locators text isn't "+valueComparisonString+" some value specified");
                t5.addLineToDataBottom("Locators and their unexpected text:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingText){
                    t5.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t5.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t5.addLineToDataBottom(v);
                }
                throw t5;
            }
        }





        /// <summary>
        /// Compares a specified attribute of the specified locators to the specified set of values.
        /// For positive compare types, a single satisfied comparison will return.
        /// For negative compare types, a single unsatisfied comparison will throw a TestAssertionException.
        /// 
        /// Will throw a TestAssertionException if no locators specified exist.
        /// Will throw argument exceptions if no locators or values are specified 
        /// </summary>
        /// <param name="locators"></param>
        /// <param name="compareType"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public void assertLocatorAttribute(String[] locators, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String attribute, String[] values) {
            
            if (locators == null) {
                throw new ArgumentNullException("locators", "Locators must not be null.");
            }
            if (locators.Length < 1) {
                throw new ArgumentException("locators", "At least one locator must be supplied.");
            }
            if (values == null) {
                throw new ArgumentNullException("values", "At least one value must be supplied.");
            }
            if (values.Length < 1) {
                throw new ArgumentException("values", "At least one value must be supplied.");
            }

            List<KeyValuePair<String, String>> locatorsAndUnmatchingAttribute = new List<KeyValuePair<string,string>>();
            List<KeyValuePair<String, String>> locatorsAndMatchingAttribute   = new List<KeyValuePair<string,string>>();
            
            //better data struct?
            String valueComparisonString = compareType.ToString();

            switch (existType) {
                case Set.All:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try{
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    }catch (SeleniumException ) {}//if attribute doesn't exist, sel exception is thrown and string remains null
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (!comparisonMet) {
                        locatorsAndUnmatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                    }
                }
                if(locatorsAndUnmatchingAttribute.Count == 0){
                    return;
                }
                TestAssertionException t0 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                t0.addLineToDataBottom("Expected: all locators "+attribute+" attribute value "+valueComparisonString+" some value specified");
                t0.addLineToDataBottom("Locators and their unexpected attribute value:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingAttribute){
                    t0.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t0.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t0.addLineToDataBottom(v);
                }
                throw t0;

                case Set.AllNone:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try{
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    }catch (SeleniumException ) {}//if attribute doesn't exist, sel exception is thrown and string remains null
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        locatorsAndMatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                    } else {
                        locatorsAndUnmatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                    }
                    if (locatorsAndMatchingAttribute.Count > 0 && locatorsAndUnmatchingAttribute.Count > 0) {
                        TestAssertionException t1 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                        t1.addLineToDataBottom("Expected: all or no locators "+attribute+" attribute value "+valueComparisonString+" some value specified");
                        t1.addLineToDataBottom("Locators and their unexpected attribute value:");
                        foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingAttribute){
                            t1.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                        }
                        foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingAttribute){
                            t1.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                        }
                        t1.addLineToDataBottom("Specified values:");
                        foreach (String v in values) {
                            t1.addLineToDataBottom(v);
                        }
                        throw t1;
                    }
                }
                return;
                
                case Set.AllSome:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try{
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    }catch (SeleniumException ) {}//if attribute doesn't exist, sel exception is thrown and string remains null
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            return;
                        }
                    }
                    locatorsAndUnmatchingAttribute.Add(new KeyValuePair<string, string>(locator, locatorAttributeValue));
                }
                TestAssertionException t2 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                t2.addLineToDataBottom("Expected: One or more locators "+attribute+" attribute value "+valueComparisonString+" some value specified");
                t2.addLineToDataBottom("Locators and their unexpected attribute value:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingAttribute){
                    t2.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t2.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t2.addLineToDataBottom(v);
                }
                throw t2;
                
                case Set.None:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try{
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    }catch (SeleniumException ) {}//if attribute doesn't exist, sel exception is thrown and string remains null

                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            locatorsAndMatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                            break;
                        }
                    }
                }
                if(locatorsAndMatchingAttribute.Count > 0){
                    TestAssertionException t3 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                    t3.addLineToDataBottom("Expected: No locators "+attribute+" attribute value "+valueComparisonString+" some value specified");
                    t3.addLineToDataBottom("Locators and their unexpected attribute value:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingAttribute){
                        t3.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t3.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t3.addLineToDataBottom(v);
                    }
                    throw t3;
                }
                return;

                case Set.Some:                
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try{
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    }catch (SeleniumException ) {}//if attribute doesn't exist, sel exception is thrown and string remains null
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        locatorsAndMatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                    } else {
                        locatorsAndUnmatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                    }
                    if (locatorsAndMatchingAttribute.Count > 0 && locatorsAndUnmatchingAttribute.Count > 0) {
                        return;
                    }
                }                
                if(locatorsAndMatchingAttribute.Count == 0){
                    TestAssertionException t4 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                    t4.addLineToDataBottom("Expected: One locators "+attribute+" attribute value "+valueComparisonString+" and one locators text isn't "+valueComparisonString+" some value specified");
                    t4.addLineToDataBottom("Locators and their unexpected attribute value:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingAttribute){
                        t4.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t4.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t4.addLineToDataBottom(v);
                    }
                    throw t4;
                }else{
                    TestAssertionException t4 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                    t4.addLineToDataBottom("Expected: One locators "+attribute+" attribute value "+valueComparisonString+" and one locators text isn't "+valueComparisonString+" some value specified");
                    t4.addLineToDataBottom("Locators and their unexpected attribute:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingAttribute){
                        t4.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t4.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t4.addLineToDataBottom(v);
                    }
                    throw t4;
                }                
                
                case Set.SomeNone:
                foreach (String locator in locators) {
                    String locatorAttributeValue = null;
                    try{
                        locatorAttributeValue = GetAttribute(locator + "@" + attribute);
                    }catch (SeleniumException ) {}//if attribute doesn't exist, sel exception is thrown and string remains null
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(locatorAttributeValue, value, compareType)) {
                            comparisonMet = true;
                            locatorsAndMatchingAttribute.Add(new KeyValuePair<string,string>(locator, locatorAttributeValue));
                            break;
                        }
                    }
                    if (comparisonMet == false) {
                        return;
                    }
                }
                TestAssertionException t5 = new TestAssertionException(existType, compareType, TextContentType.LocatorAttribute);
                t5.addLineToDataBottom("Expected: One or more locators "+attribute+" attribute value isn't "+valueComparisonString+" some value specified");
                t5.addLineToDataBottom("Locators and their unexpected value:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingAttribute){
                    t5.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t5.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t5.addLineToDataBottom(v);
                }
                throw t5;
            }
        }








        /// <summary>
        /// Searches all available CSS files for each selector specified,
        /// and asserts the set of selectors matches the set equality type specified.
        /// 
        /// Currently, the js function is extremely suboptimal. It searches the entire CSS 
        /// selector set for a single selector in question then repeats for the next selector
        /// specified for a O(s^2) cost.
        /// </summary>
        /// <param name="selector">The element type for which the CSS styling is applied</param>
        /// <param name="existType"></param>
        /// <param name="browser">Needed to know how to create the js call to the browser </param>
        /// <returns></returns>
        public void assertCssSelectorExistence(String[] selectors, AugmentedSelenium.Set existType, SeleniumServer.Browser browser) {
            if (selectors == null) {
                throw new ArgumentNullException("selectors", "At least one locator must be supplied.");
            }
            if (selectors.Length < 1) {
                throw new ArgumentException("selectors", "At least one locator must be supplied.");
            }
            String cssRules = "";
            switch (browser) {
                case SeleniumServer.Browser.Firefox:
                cssRules = "cssRules";
                break;
                case SeleniumServer.Browser.IExplore:
                cssRules = "rules";
                break;
            }
            String jsTop = @"  var elementExists = 'false';
                            for(var x = 0; x < window.document.styleSheets.length; x++){
                                for(var y = 0; y < window.document.styleSheets[x]." + cssRules + @".length; y++){
                                    if(window.document.styleSheets[x]." + cssRules + @"[y].selectorText == '";

            String jsBottom = @"'){
                                        elementExists = 'true';
                                    }
                                }
                            }
                            elementExists;";

            
            switch (existType) {
                case Set.All:
                    LinkedList<String> missingSelectors = new LinkedList<string>();
                    foreach (String s in selectors) {
                        if (!(GetEval(jsTop + s + jsBottom).Equals("true"))) {
                            missingSelectors.AddLast(s);
                        }
                    }
                    if (missingSelectors.Count > 0) {
                        TestAssertionException t0 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.HasCSS);
                        try {
                            t0.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) {
                            //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                        }
                        foreach (String selector in missingSelectors) {
                            t0.addLineToDataBottom("Expected css selector : " + selector);
                        }
                        throw t0;
                    }
                return;
                case Set.AllSome:
                    foreach (String s in selectors) {
                        if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                            return;
                        }
                    }
                    TestAssertionException t1 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.HasCSS);
                    try {
                        t1.addLineToDataBottom("Current URL : " + GetLocation());
                    } catch (SeleniumException ) {
                        //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                    }
                    t1.addLineToDataBottom("Expected at least one following selectors :");
                    foreach (String selector in selectors) {
                        t1.addLineToDataBottom("Selector : " + selector);
                    }
                    throw t1;

                case Set.Some:
                    LinkedList<String> existingLocators = new LinkedList<string>();
                    LinkedList<String> notExistingLocators = new LinkedList<string>();
                    foreach (String s in selectors) {
                        if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                            existingLocators.AddLast(s);
                        } else {
                            notExistingLocators.AddLast(s);
                        }
                    }
                    if (existingLocators.Count > 0 && notExistingLocators.Count > 0) {
                        return;
                    }
                    if (notExistingLocators.Count == 0) {
                        TestAssertionException t2 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.NotHasCSS);
                        try {
                            t2.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) {
                            //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                        }
                        t2.addLineToDataBottom("Expected at least one selector to not exist:");
                        foreach (String selector in selectors) {
                            t2.addLineToDataBottom("Selector : " + selector);
                        }
                        throw t2;
                    } else {
                        TestAssertionException t2 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.HasCSS);
                        try {
                            t2.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) {
                            //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                        }
                        t2.addLineToDataBottom("Expected at least one selector to exist:");
                        foreach (String selector in selectors) {
                            t2.addLineToDataBottom("Selector : " + selector);
                        }
                        throw t2;
                    }
                
                case Set.None:
                    LinkedList<String> existingSelectors1 = new LinkedList<string>();
                    foreach (String s in selectors) {
                        if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                            existingSelectors1.AddLast(s);
                        }
                    }
                    if (existingSelectors1.Count > 0) {
                        TestAssertionException t3 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.NotHasCSS);
                        try {
                            t3.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) {
                            //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                        }
                        foreach (String selector in existingSelectors1) {
                            t3.addLineToDataBottom("Unexpected selector : " + selector);
                        }
                        throw t3;
                    }
                return;
                case Set.AllNone:
                    LinkedList<String> existingSelectors2 = new LinkedList<string>();
                    LinkedList<String> notExistingSelectors2 = new LinkedList<string>();
                    foreach (String s in selectors) {
                        if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                            existingSelectors2.AddLast(s);
                        } else {
                            notExistingSelectors2.AddLast(s);
                        }
                    }
                    if (existingSelectors2.Count > 0 && notExistingSelectors2.Count > 0) {
                        TestAssertionException t4 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.HasCSS);
                        try {
                            t4.addLineToDataBottom("Current URL : " + GetLocation());
                        } catch (SeleniumException ) {
                            //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                        }
                        t4.addLineToDataBottom("Expected all or no selectors to exist, not some: ");
                        foreach (String locator in existingSelectors2) {
                            t4.addLineToDataBottom("Existing selector : " + locator);
                        }
                        foreach (String locator in notExistingSelectors2) {
                            t4.addLineToDataBottom("Not existing selector : " + locator);
                        }
                        throw t4;
                    }
                return;
                case Set.SomeNone:
                    foreach (String s in selectors) {
                        if (!GetEval(jsTop + s + jsBottom).Equals("true")) {// or "false"
                            return;
                        }
                    }
                    TestAssertionException t5 = new TestAssertionException(TestAssertionException.AssertionTypeEnum.NotHasCSS);
                    try {
                        t5.addLineToDataBottom("Current URL : " + GetLocation());
                    } catch (SeleniumException ) {
                        //do nothing, reporting failures of attempts to report failures isn't helpful, just leave out missing info
                    }
                    t5.addLineToDataBottom("Expect at least one following selectors to not exist :");
                    foreach (String locator in selectors) {
                        t5.addLineToDataBottom("Selector : " + locator);
                    }
                    throw t5;

                default:
                return;
            }
        }








        /// <summary>
        /// Searches all available CSS files for each selector specified,
        /// and asserts the set of selectors matches the comparisonType specified
        /// for some property and a set of values. Can throw argument exceptions if
        /// the set of selectors and values are empty
        /// </summary>
        /// <param name="selectors"></param>
        /// <param name="compareType"></param>
        /// <param name="property"></param>
        /// <param name="values"></param>
        /// <param name="browser"></param>
        public void assertCssSelectorProperty(String[] selectors, AugmentedSelenium.Set existType, AugmentedSelenium.Compare compareType, String property, String[] values, SeleniumServer.Browser browser) {
            if (selectors == null) {
                throw new ArgumentNullException("selectors", "selectors must not be null.");
            }
            if (values == null) {
                throw new ArgumentNullException("values", "At least one value must be supplied.");
            }
            if (values.Length < 1) {
                throw new ArgumentException("values", "At least one value must be supplied.");
            }

            List<KeyValuePair<String, String>> locatorsAndUnmatchingProperty = new List<KeyValuePair<string,string>>();
            List<KeyValuePair<String, String>> locatorsAndMatchingProperty   = new List<KeyValuePair<string,string>>();
            
            String valueComparisonString = compareType.ToString();

            String cssRules = "";
            switch (browser) {
                case SeleniumServer.Browser.Firefox:
                cssRules = "cssRules";
                break;
                case SeleniumServer.Browser.IExplore:
                cssRules = "rules";
                break;
            }
            String jsTop = @" var cssSelectorPropertyValue = 'ThisSelectorDoesNotExist';
                            for(var x = 0; x < window.document.styleSheets.length; x++){
                                for(var y = 0; y < window.document.styleSheets[x]." + cssRules + @".length; y++){
                                    if(window.document.styleSheets[x]." + cssRules + @"[y].selectorText == '"; /* + selector + */ 
            String jsBottom = @"'){
                                        cssSelectorPropertyValue = window.document.styleSheets[x]." + cssRules + @"[y].style."+property+@";
                                    }
                                }
                            }
                            cssSelectorPropertyValue;";
            //JS problem: Null cannot be returned from the js side of things, so if the selector doesn't even exists it would just return '', 
            //which is ambigous with selectors that exist and are ''.
            //workaround the problem of not first checking if the selector exists and losing that info when returning '' from the js:
            //set the return value to something uniquely recognizable initially, then watch for that text and then set the string to null.
            //very unlikely that the constant value used would ever show up and get treated as null

            switch (existType) {
                case Set.All:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (!comparisonMet) {
                        locatorsAndUnmatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                    }
                }
                if(locatorsAndUnmatchingProperty.Count == 0){
                    return;
                }
                TestAssertionException t0 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                t0.addLineToDataBottom("Expected: all selectors "+ property+" property value "+valueComparisonString+" some value specified");
                t0.addLineToDataBottom("Selectors and their unexpected property value:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingProperty){
                    t0.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t0.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t0.addLineToDataBottom(v);
                }
                throw t0;

                case Set.AllNone:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        locatorsAndMatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                    } else {
                        locatorsAndUnmatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                    }
                    if (locatorsAndMatchingProperty.Count > 0 && locatorsAndUnmatchingProperty.Count > 0) {
                        TestAssertionException t1 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                        t1.addLineToDataBottom("Expected: all or no "+ property+" property value "+valueComparisonString+" some value specified");
                        t1.addLineToDataBottom("Selectors and their unexpected property value:");
                        foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingProperty){
                            t1.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                        }
                        foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingProperty){
                            t1.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                        }
                        t1.addLineToDataBottom("Specified values:");
                        foreach (String v in values) {
                            t1.addLineToDataBottom(v);
                        }
                        throw t1;
                    }
                }
                return;
                
                case Set.AllSome:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            return;
                        }
                    }
                    locatorsAndUnmatchingProperty.Add(new KeyValuePair<string, string>(selector, selectorPropertyValue));
                }
                TestAssertionException t2 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                t2.addLineToDataBottom("Expected: One or more "+ property+" property value "+valueComparisonString+" some value specified");
                t2.addLineToDataBottom("Selectors and their unexpected property value:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingProperty){
                    t2.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t2.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t2.addLineToDataBottom(v);
                }
                throw t2;
                
                case Set.None:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            locatorsAndMatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                            break;
                        }
                    }
                }
                if(locatorsAndMatchingProperty.Count > 0){
                    TestAssertionException t3 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                    t3.addLineToDataBottom("Expected: No "+ property+" property value "+valueComparisonString+" some value specified");
                    t3.addLineToDataBottom("Selectors and their unexpected property value:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingProperty){
                        t3.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t3.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t3.addLineToDataBottom(v);
                    }
                    throw t3;
                }
                return;

                case Set.Some:                
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            break;
                        }
                    }
                    if (comparisonMet) {
                        locatorsAndMatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                    } else {
                        locatorsAndUnmatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                    }
                    if (locatorsAndMatchingProperty.Count > 0 && locatorsAndUnmatchingProperty.Count > 0) {
                        return;
                    }
                }                
                if(locatorsAndMatchingProperty.Count == 0){
                    TestAssertionException t4 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                    t4.addLineToDataBottom("Expected: One "+ property+" property value "+valueComparisonString+" and one locators text isn't "+valueComparisonString+" some value specified");
                    t4.addLineToDataBottom("Selectors and their unexpected property value:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndUnmatchingProperty){
                        t4.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t4.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t4.addLineToDataBottom(v);
                    }
                    throw t4;
                }else{
                    TestAssertionException t4 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                    t4.addLineToDataBottom("Expected: One "+ property+" property value "+valueComparisonString+" and one locators text isn't "+valueComparisonString+" some value specified");
                    t4.addLineToDataBottom("Selectors and their unexpected property value:");
                    foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingProperty){
                        t4.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                    }
                    t4.addLineToDataBottom("Specified values:");
                    foreach (String v in values) {
                        t4.addLineToDataBottom(v);
                    }
                    throw t4;
                }                
                
                case Set.SomeNone:
                foreach (String selector in selectors) {
                    String selectorPropertyValue = GetEval(jsTop + selector + jsBottom);
                    if (selectorPropertyValue.Equals("ThisSelectorDoesNotExist")) {
                        selectorPropertyValue = null;
                    }
                    bool comparisonMet = false;
                    foreach (String value in values) {
                        if (textComparer(selectorPropertyValue, value, compareType)) {
                            comparisonMet = true;
                            locatorsAndMatchingProperty.Add(new KeyValuePair<string,string>(selector, selectorPropertyValue));
                            break;
                        }
                    }
                    if (comparisonMet == false) {
                        return;
                    }
                }
                TestAssertionException t5 = new TestAssertionException(existType, compareType, TextContentType.SelectorProperty);
                t5.addLineToDataBottom("Expected: One or more "+ property+" property value isn't "+valueComparisonString+" some value specified");
                t5.addLineToDataBottom("Selectors and their unexpected property value:");
                foreach(KeyValuePair<String, String> kvp in locatorsAndMatchingProperty){
                    t5.addLineToDataBottom(kvp.Key + " : " + kvp.Value);
                }
                t5.addLineToDataBottom("Specified values:");
                foreach (String v in values) {
                    t5.addLineToDataBottom(v);
                }
                throw t5;
            }
        }



        #endregion



        #region user extension wrapper methods
        public void SubmitForm( String formLocator ) {
            this.runProcCommand( "submitForm", new String[] { formLocator } );
        }

        #endregion




        /// <summary>
        /// Opens a blank page using the specific implementation used by each browser
        /// </summary>
        /// <param name="browser"></param>
        public void openBlankPage(SeleniumServer.Browser browser) {
            String url;
            switch (browser) {
                case SeleniumServer.Browser.IExplore:
                url = @"about:blank";
                break;
                case SeleniumServer.Browser.Firefox:
                url = @"about:blank";
                break;
                default:
                url = @"about:blank";//May work with all browser types I support, making this logic pointless
                break;
            }
            Open(url);
            WaitForPageToLoad("25000");
        }

        public bool openIfNotAt(String URL, bool ignoreQueryParams) {
            String location = "";
            try {
                location = GetLocation();
            } catch (SeleniumException) {
                //NOTE: this fails to open if the window is closed. Investigate later
                Open(URL);
                return true;
            }

            if (ignoreQueryParams) {
                location = location.Split(new char[] { '?', ';' })[0];
            }
            if (!URL.Equals(location)) {
                Open(URL);
                return true;
            }
            return false;
        }

        /// <summary>
        /// This opens a page and waits for it to load and verifies location is the URL specified
        /// </summary>
        /// <param name="url">The full location</param>
        /// <param name="reopenEvenIfOnPage">A flag that controls logic to determine whether or not to call the open command if the current location is the same as the URL specified</param>
        /// <param name="ignoreQueryParams">A flag that controls logic to determine whether or not to ignore everything after the path of the current URL when comparing it to the supplied URL</param>
        public void openPage(String url, bool reopenEvenIfOnPage, bool ignoreQueryParams) {
            if (reopenEvenIfOnPage) {
                Open(url);
                WaitForPageToLoad("25000");
                assertPresentLocation(  url, true );
            } else {
                if (openIfNotAt(url, ignoreQueryParams)) {
                    WaitForPageToLoad("25000");
                    assertPresentLocation(  url, true );
                }
            }
        }

        /// <summary>
        /// POSTs to the following url with the parameters specified. Waits for a page to load
        /// </summary>
        /// <param name="url">The page which the parameters are sent</param>
        /// <param name="postParams"></param>
        public void openPost(String url, List<KeyValuePair<String, String>> postParams) {
            //exception catching, sanitization of parameters for js (quotation marks specifically)
            String postRequest = @"
                var form = window.document.createElement(""form"");
                form.setAttribute(""name"", ""seleniumPost"");
                form.setAttribute(""method"", ""post"");
                form.setAttribute(""action"", """ + url + @""");
            ";

            foreach (KeyValuePair<String, String> kvp in postParams) {
                postRequest += @"
                    var hiddenField" + kvp.Key + @" = window.document.createElement(""input"");
                    hiddenField" + kvp.Key + @".setAttribute(""type"", ""hidden"");
                    hiddenField" + kvp.Key + @".setAttribute(""name"", """ + kvp.Key + @""");
                    hiddenField" + kvp.Key + @".setAttribute(""value"", """ + kvp.Value + @""");
                    form.appendChild(hiddenField" + kvp.Key + @");
                ";
            }

            postRequest += @"
                window.document.body.appendChild(form);
                var formInfo = ""parent: ""+window.document.getElementsByName(""seleniumPost"")[0].parentNode.nodeName;
                formInfo;";
            String returnString = GetEval(postRequest);
            SubmitForm( @"//form[@name='seleniumPost']" );
            WaitForPageToLoad("25000");
        }

        public void tryWaitForURLToBe(String URL, int timeout, int interval) {
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (!GetLocation().Equals(URL) && DateTime.Compare(start, DateTime.Now) > 0) {
                timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
        }

        public void tryWaitForJSFunctionToExist(String functionName, int timeout, int interval) {
            String jsEvaluation = "var exists; exists =window." + functionName + "; exists;";
            DateTime start = DateTime.Now.AddMilliseconds((double)timeout);
            while (GetEval(jsEvaluation).Equals("false") && DateTime.Compare(start, DateTime.Now) > 0) {
                timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
        }

        /// <summary>
        /// Goes through a list of locators and returns the first one found.
        /// Only goes through once, so if none exist at the time of checking,
        /// null is returned.
        /// </summary>
        /// <param name="locators"></param>
        /// <returns></returns>
        public String getFirstExistingElement(String[] locators) {
            foreach (String s in locators) {
                if (IsElementPresent(s)) {
                    return s;
                }
            }
            return null;
        }

        /// <summary>
        /// Returns a list of all locators that were found to exist from a supplied set of locators
        /// throws argument exceptions if the set of locators are empty or null
        /// </summary>
        /// <param name="locators"></param>
        /// <returns></returns>
        public String[] getAllExistingLocators(String[] locators) {
            if (locators == null) {
                throw new ArgumentNullException("locators", "At least one locator must be supplied.");
            }
            if (locators.Length < 1) {
                throw new ArgumentException("locators", "At least one locator must be supplied.");
            }
            List<String> existingLocators = new List<string>();
            foreach (String s in locators) {
                if (IsElementPresent(s)) {
                    existingLocators.Add(s);
                }
            }
            return existingLocators.ToArray();
        }

        /// <summary>
        /// Returns a list of all selectors that were found to exist from a supplied set of selector
        /// throws argument exceptions if the set of selector are empty or null
        /// </summary>
        /// <param name="locators"></param>
        /// <returns></returns>
        public String[] getAllExistingCssSelectors(String[] selectors, SeleniumServer.Browser browser) {
            if (selectors == null) {
                throw new ArgumentNullException("selectors", "At least one selector must be supplied.");
            }
            if (selectors.Length < 1) {
                throw new ArgumentException("selectors", "At least one selector must be supplied.");
            }

            String cssRules = "";
            switch (browser) {
                case SeleniumServer.Browser.Firefox:
                cssRules = "cssRules";
                break;
                case SeleniumServer.Browser.IExplore:
                cssRules = "rules";
                break;
            }
            String jsTop = @"  var elementExists = 'false';
                            for(var x = 0; x < window.document.styleSheets.length; x++){
                                for(var y = 0; y < window.document.styleSheets[x]." + cssRules + @".length; y++){
                                    if(window.document.styleSheets[x]." + cssRules + @"[y].selectorText == '";

            String jsBottom = @"'){
                                        elementExists = 'true';
                                    }
                                }
                            }
                            elementExists;";


            List<String> existingSelectors = new List<string>();
            foreach (String s in selectors) {
                if (GetEval(jsTop + s + jsBottom).Equals("true")) {
                    existingSelectors.Add(s);
                }
            }
            return existingSelectors.ToArray();
        }

        /// <summary>
        /// Can throw SeleniumExceptions and TestAssertionExceptions. SeleniumExceptions are caused by failures in attempting to determine
        /// an assertion and are not handled. No SeleniumExceptions can happen as a result of trying to report on success or failure of the 
        /// operation. Also theoretically throws Argument and ArgumentNullExceptions but if GetLocation() returns null, I suspect would have 
        /// thrown a SeleniumException so there is no way for this to happen.
        /// </summary>
        /// <param name="URL">The full URL and http protocol prefix</param>
        public void assertPresentLocation(String URL) {
            String currentLocation = GetLocation();
            if(currentLocation.EndsWith(@"/")){
                currentLocation = currentLocation.Substring(0, currentLocation.Length - 1);
            }
            if (URL.EndsWith(@"/")) {
                URL = URL.Substring(0, URL.Length - 1);
            }
            if (!currentLocation.Equals(URL)) {
                TestAssertionException t = new TestAssertionException(TestAssertionException.AssertionTypeEnum.AtLocation);
                t.addLineToDataBottom("Current URL : " + currentLocation);
                t.addLineToDataBottom("Expected URL : " + URL);
                throw t;
            }
        }

        public void assertPresentLocation(String[] acceptedURLS, bool ignoreQueryParams) {
            String currentLocation = GetLocation();
            if (ignoreQueryParams) {
                currentLocation = currentLocation.Split(new char[] { '?', ';' })[0];
            }
            if (currentLocation.EndsWith(@"/")) {
                currentLocation = currentLocation.Substring(0, currentLocation.Length - 1);
            }

            bool matches = false;
            foreach (String url in acceptedURLS) {
                String formattedURL = url;
                if (formattedURL.EndsWith(@"/")) {
                    formattedURL = formattedURL.Substring(0, formattedURL.Length - 1);
                }
                if (String.Compare(currentLocation, formattedURL, true) == 0) {
                    matches = true;
                }
            }

            if (!matches) {
                TestAssertionException t = new TestAssertionException(TestAssertionException.AssertionTypeEnum.AtLocation);
                t.addLineToDataBottom("Current URL : " + currentLocation);
                foreach (String url in acceptedURLS) {
                    String formattedURL = url;
                    if (formattedURL.EndsWith(@"/")) {
                        formattedURL = formattedURL.Substring(0, formattedURL.Length - 1);
                    }
                    t.addLineToDataBottom("Expected URL : " + formattedURL);
                }
                throw t;
            }
        }

        public void assertPresentLocation( String URL, bool ignoreQueryParams) {
            String currentLocation = GetLocation();
            if (ignoreQueryParams) {
                currentLocation = currentLocation.Split(new char[] { '?', ';' })[0];
            }
            if (currentLocation.EndsWith(@"/")) {
                currentLocation = currentLocation.Substring(0, currentLocation.Length - 1);
            }
            if (URL.EndsWith(@"/")) {
                URL = URL.Substring(0, URL.Length - 1);
            }

            if (!currentLocation.Equals(URL)) {
                TestAssertionException t = new TestAssertionException(TestAssertionException.AssertionTypeEnum.AtLocation);
                t.addLineToDataBottom("Current URL : " + currentLocation);
                t.addLineToDataBottom("Expected URL : " + URL);
                throw t;
            }
        }

        public void assertPresentLocation( OrderPath path, bool ignoreQueryParams ) {
            String expectedLocation = path.URL;
            String currentLocation = GetLocation();
            if ( ignoreQueryParams ) {
                currentLocation = currentLocation.Split( new char[] { '?', ';' } )[0];
            }
            if ( currentLocation.EndsWith( @"/" ) ) {
                currentLocation = currentLocation.Substring( 0, currentLocation.Length - 1 );
            }
            if ( expectedLocation.EndsWith( @"/" ) ) {
                expectedLocation = expectedLocation.Substring( 0, expectedLocation.Length - 1 );
            }
            if ( path.SignUpOverlay ) {//add overloaded version with path
                expectedLocation = expectedLocation.Replace( @"/rhapsody", @"/order/rhapsody" );//the upsell overlay path URLs add 'order' on in page error... yet one more variation to deal with
            }

            if ( !currentLocation.Equals( expectedLocation ) ) {
                TestAssertionException t = new TestAssertionException( TestAssertionException.AssertionTypeEnum.AtLocation );
                t.addLineToDataBottom( "Current URL : " + currentLocation );
                t.addLineToDataBottom( "Expected URL : " + expectedLocation );
                throw t;
            }
        }
    }
}
